//
//  ViewController.m
//  ReactiveObjCDemo
//
//  Created by jianzhao4 on 2017/9/5.
//  Copyright © 2017年 Xwoder. All rights reserved.
//

#import "ViewController.h"
#import <ReactiveObjC/ReactiveObjC.h>
#import <ReactiveObjC/RACReturnSignal.h>
#import "LoginService.h"
#import "MyView.h"
#import <Masonry/Masonry.h>
#import "County.h"
#import "HUDManager.h"

@interface ViewController ()

@property (nonatomic, strong) RACCommand<NSString *, NSString *> *command;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // [self demo1];
    // [self demo2];
    // [self demo3];
    // [self demo4];
    // [self demo5];
    // [self demo6];
    // [self demo7];
    // [self demo8];
    // [self demo10];
    // [self demo11];
    // [self demo12];
    // [self demo13];
    // [self demo14];
    // [self demo15];
    // [self demo16];
    // [self demo17];
    // [self demo18];
    // [self demo19];
    // [self demo20];
    // [self demo21];
    // [self demo22];
    // [self demo23];
    // [self demo24];
    // [self demo25];
    // [self demo26];
    // [self demo27];
    // [self demo28];
    // [self demo29];
    // [self demo30];
    // [self demo31];
    [self demo32];
}

- (void)demo1 {
    UITextField *usernameTextField = [[UITextField alloc] init];
    usernameTextField.borderStyle = UITextBorderStyleRoundedRect;
    usernameTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:usernameTextField];
    [usernameTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    // UITextField 的 rac_textSignal 属性定义在 UITextField+RACSignalSupport.h 头文件中
    [usernameTextField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"x = %@", x);
    }];
    // 在 usernameTextField 中依次输入：1、2、3、4、5
    // 输出
    // x = 1
    // x = 12
    // x = 123
    // x = 1234
    // x = 12345
}

- (void)demo2 {
    UITextField *usernameTextField = [[UITextField alloc] init];
    usernameTextField.borderStyle = UITextBorderStyleRoundedRect;
    usernameTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:usernameTextField];
    [usernameTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    [[usernameTextField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
        return value.length >= 7;
    }] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"x = %@", x);
    }];
    // 在 usernameTextField 中依次输入：1、2、3、4、5
    // 输出
    // x = 123
    // x = 1234
    // x = 12345
}

- (void)demo3 {
    UITextField *usernameTextField = [[UITextField alloc] init];
    usernameTextField.borderStyle = UITextBorderStyleRoundedRect;
    usernameTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:usernameTextField];
    [usernameTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    // 对 demo2 方法中的管道分解
    RACSignal *usernameSignal = usernameTextField.rac_textSignal;
    RACSignal *usernameSignalFiltered = [usernameSignal filter:^BOOL(NSString * _Nullable value) {
        return value.length >= 7;
    }];
    
    [usernameSignalFiltered subscribeNext:^(id  _Nullable x) {
        NSLog(@"x = %@", x);
    }];
}

- (void)demo4 {
    UITextField *usernameTextField = [[UITextField alloc] init];
    usernameTextField.borderStyle = UITextBorderStyleRoundedRect;
    usernameTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:usernameTextField];
    [usernameTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    // RACSignal -> map -> filter -> subscribe
    [[[usernameTextField.rac_textSignal map:^NSNumber * _Nullable(NSString * _Nullable value) {
        return @(value.length);
    }] filter:^BOOL(NSNumber * _Nullable value) {
        return value.unsignedIntegerValue >= 7;
    }] subscribeNext:^(NSNumber * _Nullable x) {
        NSLog(@"x = %@", x);
    }];
}

- (void)demo5 {
    UITextField *emailTextField = [[UITextField alloc] init];
    emailTextField.borderStyle = UITextBorderStyleRoundedRect;
    emailTextField.placeholder = @"E-mail";
    emailTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:emailTextField];
    [emailTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    UITextField *passwordTextField = [[UITextField alloc] init];
    passwordTextField.borderStyle = UITextBorderStyleRoundedRect;
    passwordTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:passwordTextField];
    [passwordTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.and.right.equalTo(emailTextField);
        make.top.equalTo(emailTextField.mas_bottom).mas_equalTo(8);
    }];
    
    // RACSignal -> map -> map -> subscribe
    [[[emailTextField.rac_textSignal map:^NSNumber * _Nullable(NSString * _Nullable email) {
        return @([email containsString:@"@"]);
    }] map:^UIColor * _Nullable(NSNumber * _Nullable validUsername) {
        return validUsername.boolValue ? [UIColor clearColor] : [UIColor yellowColor];
    }] subscribeNext:^(UIColor * _Nullable color) {
        emailTextField.backgroundColor = color;
    }];
    
    [[[passwordTextField.rac_textSignal map:^NSNumber * _Nullable(NSString * _Nullable password) {
        return @(password.length >= 6);
    }] map:^UIColor * _Nullable(NSNumber * _Nullable validPassword) {
        return validPassword.boolValue ? [UIColor clearColor] : [UIColor yellowColor];
    }] subscribeNext:^(UIColor * _Nullable color) {
        passwordTextField.backgroundColor = color;
    }];
}

- (void)demo6 {
    UITextField *emailTextField = [[UITextField alloc] init];
    emailTextField.borderStyle = UITextBorderStyleRoundedRect;
    emailTextField.placeholder = @"E-mail";
    emailTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:emailTextField];
    [emailTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    UITextField *passwordTextField = [[UITextField alloc] init];
    passwordTextField.borderStyle = UITextBorderStyleRoundedRect;
    passwordTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:passwordTextField];
    [passwordTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.and.right.equalTo(emailTextField);
        make.top.equalTo(emailTextField.mas_bottom).mas_equalTo(8);
    }];
    
    RAC(emailTextField, backgroundColor) = [[emailTextField.rac_textSignal map:^NSNumber * _Nullable(NSString * _Nullable email) {
        return @([email containsString:@"@"]);
    }] map:^UIColor * _Nullable(NSNumber * _Nullable validUsername) {
        return validUsername.boolValue ? [UIColor clearColor] : [UIColor yellowColor];
    }];
    
    RAC(passwordTextField, backgroundColor) = [[passwordTextField.rac_textSignal map:^NSNumber * _Nullable(NSString * _Nullable password) {
        return @(password.length >= 6);
    }] map:^UIColor * _Nullable(NSNumber * _Nullable validPassword) {
        return validPassword.boolValue ? [UIColor clearColor] : [UIColor yellowColor];
    }];
}

- (void)demo7 {
    UITextField *emailTextField = [[UITextField alloc] init];
    emailTextField.borderStyle = UITextBorderStyleRoundedRect;
    emailTextField.placeholder = @"E-mail";
    emailTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:emailTextField];
    [emailTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    UITextField *passwordTextField = [[UITextField alloc] init];
    passwordTextField.borderStyle = UITextBorderStyleRoundedRect;
    passwordTextField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:passwordTextField];
    [passwordTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.and.right.equalTo(emailTextField);
        make.top.equalTo(emailTextField.mas_bottom).mas_equalTo(8);
    }];
    
    UIButton *loginButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [loginButton setTitle:@"Button" forState:UIControlStateNormal];
    [self.view addSubview:loginButton];
    [loginButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.and.right.equalTo(passwordTextField);
        make.top.equalTo(passwordTextField.mas_bottom).mas_equalTo(8);
    }];
    
    RACSignal *usernameValidSignal = [emailTextField.rac_textSignal map:^NSNumber * _Nullable(NSString * _Nullable email) {
        return @([email containsString:@"@"]);
    }];
    
    RACSignal *passwordValidSignal = [passwordTextField.rac_textSignal map:^NSNumber * _Nullable(NSString * _Nullable password) {
        return @(password.length >= 6);
    }];
    // 合并多个信号为单个信号
    RACSignal *loginValidSignal = [RACSignal combineLatest:@[usernameValidSignal, passwordValidSignal]
                                                    reduce:^NSNumber * _Nullable(NSNumber *usernameValid, NSNumber *passwordValid) {
                                                        return @(usernameValid.boolValue && passwordValid.boolValue);
                                                    }];
    
    RAC(loginButton, backgroundColor) = [loginValidSignal map:^UIColor * _Nullable(NSNumber * _Nullable loginValid) {
        return loginValid.boolValue ? [UIColor greenColor] : [UIColor redColor];
    }];
}

- (void)demo8 {
    UIButton *loginButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [loginButton setTitle:@"Button" forState:UIControlStateNormal];
    [self.view addSubview:loginButton];
    [loginButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    [[loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable button) {
        NSLog(@"Button pressed, x = %@", button);
    }];
}

/** 手势 */
- (void)demo10 {
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:nil action:nil];
    tap.numberOfTapsRequired = 3;
    [tap.rac_gestureSignal subscribeNext:^(__kindof UITapGestureRecognizer * _Nullable x) {
        NSLog(@"x = %@", x);
    }];
    [self.view addGestureRecognizer:tap];
}

- (void)demo11 {
    // RACSignal使用步骤
    // 1. 创建信号。涉及方法: + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
    // 2. 订阅信号，才会激活信号。涉及方法: - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
    // 3. 发送信号。涉及方法: - (void)sendNext:(id)value
    
    // RACSubscriber: 订阅者，用于发送信号。这是一个协议，不是一个类，只要遵守这个协议，并且实现方法才能成为订阅者。通过create创建的信号，都有一个订阅者，帮助它发送数据。
    
    // RACDisposable: 用于取消订阅或者清理资源，当信号发送完成或者发送错误的时候，就会自动触发它。
    
    RACSignal<NSString *> *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        [subscriber sendNext:@"Next"];
        [subscriber sendCompleted];
        
        return [RACDisposable disposableWithBlock:^{
            // 当信号发送完成或者发送错误，就会自动执行当前 Block；执行完 Block 后，当前信号就不再被订阅了
            NSLog(@"Disposable");
        }];
    }];
    
    [signal subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"x = %@", x);
    } completed:^{
        NSLog(@"Completed");
    }];
}

- (void)demo12 {
    
    // RACSubject: 信号提供者，自己可以充当信号，又能发送信号
    
    RACSubject *subject = [RACSubject subject];
    
    [subject subscribeNext:^(id x) {
        // block调用时刻: 当信号发出新值，就会调用.
        NSLog(@"第1个订阅者, x = %@", x);
    }];
    
    [subject subscribeNext:^(id x) {
        // block调用时刻: 当信号发出新值，就会调用.
        NSLog(@"第2个订阅者, x = %@", x);
    }];
    
    [subject sendNext:@"Hello"];
    
    [subject subscribeNext:^(id x) {
        // block调用时刻: 当信号发出新值，就会调用.
        NSLog(@"第3个订阅者, x = %@", x);
    }];
    
    // 输出
    // 第1个订阅者, x = Hello
    // 第2个订阅者, x = Hello
}

- (void)demo13 {
    // RACReplaySubject：重复提供信号类，RACSubject的子类
    // RACReplaySubject 与 RACSubject区别：RACReplaySubject可以先发送信号，在订阅信号，RACSubject就不可以。
    // 使用场景
    //     1: 如果一个信号每被订阅一次，就需要把之前的值重复发送一遍，使用重复提供信号类
    //     2: 可以设置 capacity 数量来限制缓存的 value 的数量，即只缓充最新的几个值
    
    // RACSubjec 是 RACSignal 的子类，但 RACSubject 的底层实现和 RACSignal 不一样
    // 1. 调用 subscribeNext 订阅信号，只是把订阅者保存起来，并且订阅者的 nextBlock 已经赋值了
    // 2. 调用 sendNext 发送信号，遍历刚刚保存的所有订阅者，一个一个调用订阅者的 nextBlock
    
    // RACReplaySubject与RACSubject区别
    // RACReplaySubject 可以先发送信号，再订阅信号，而 RACSubject 就不可以
    
    RACReplaySubject<NSString *> *replaySubject = [RACReplaySubject subject];
    
    [replaySubject sendNext:@"Hello"];
    [replaySubject sendNext:@"World"];
    
    [replaySubject subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"第1个订阅者, x = %@",x);
    }];
    
    [replaySubject subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"第2个订阅者, x = %@",x);
    }];
    
    [replaySubject sendNext:@"I'm coming"];
    
    // 输出
    // 第1个订阅者, x = Hello
    // 第1个订阅者, x = World
    // 第2个订阅者, x = Hello
    // 第2个订阅者, x = World
    // 第1个订阅者, x = I'm coming
    // 第2个订阅者, x = I'm coming
}

- (void)demo14 {
    MyView *myView = [[MyView alloc] init];
    myView.delegateSignal = [RACSubject subject];
    [self.view addSubview:myView];
    [myView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.size.mas_equalTo(CGSizeMake(200, 200));
        make.center.equalTo(self.view);
    }];
    
    [myView.delegateSignal subscribeNext:^(MyView * _Nullable x) {
        NSLog(@"x = %@", x);
    }];
}

- (void)demo15 {
    NSArray<NSNumber *> *arr = @[@(1), @(2), @(3), @(4), @(5)];
    
    [arr.rac_sequence.signal subscribeNext:^(NSNumber * _Nullable x) {
        NSLog(@"x.class = %@, x = %@", x.class, x);
    }];
}

- (void)demo16 {
    NSDictionary<NSString *, NSNumber *> *dic = @{ @"Jack" : @(18),
                                                   @"Tom" : @(25),
                                                   @"Lily" : @(30) };
    
    // RACTwoTuple 是 RACTuple 的子类
    [dic.rac_sequence.signal subscribeNext:^(RACTwoTuple<NSString *, NSNumber *> * _Nullable x) {
        RACTupleUnpack(NSString *name, NSNumber *age) = x;
        NSLog(@"name = %@, age = %@", name, age);
    }];
}

/** 字典转模型 - 非 RAC */
- (void)demo17 {
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"county" ofType:@"plist"];
    NSArray<NSDictionary *> *dictArr = [NSArray arrayWithContentsOfFile:filePath];
    NSMutableArray<County *> *modelArr = [NSMutableArray array];
    for (NSDictionary *dict in dictArr) {
        County *model = [County countyWithDict:dict];
        [modelArr addObject:model];
    }
    NSLog(@"modelArr = %@", modelArr);
}

/** 字典转模型 - RAC 基础写法 */
- (void)demo18 {
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"county" ofType:@"plist"];
    NSArray<NSDictionary *> *dictArr = [NSArray arrayWithContentsOfFile:filePath];
    NSMutableArray<County *> *modelArr = [NSMutableArray array];
    [dictArr.rac_sequence.signal subscribeNext:^(NSDictionary * _Nullable dict) {
        County *model = [County countyWithDict:dict];
        [modelArr addObject:model];
    } completed:^{
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"modelArr = %@", modelArr);
        }];
    }];
}

/** 字典转模型 - RAC 高级写法 */
- (void)demo19 {
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"county" ofType:@"plist"];
    NSArray<NSDictionary *> *dictArr = [NSArray arrayWithContentsOfFile:filePath];
    NSArray<County *> *modelArr = [[dictArr.rac_sequence map:^id _Nullable(NSDictionary * _Nullable dict) {
        return [County countyWithDict:dict];
    }] array];
    NSLog(@"modelArr = %@", modelArr);
}

- (void)demo20 {
    // RACCommand 类的声明
    // @interface RACCommand<__contravariant InputType, __covariant ValueType> : NSObject
    // @property (nonatomic, strong, readonly) RACSignal<RACSignal<ValueType> *> *executionSignals;
    // @property (nonatomic, strong, readonly) RACSignal<NSNumber *> *executing;
    // @property (nonatomic, strong, readonly) RACSignal<NSNumber *> *enabled;
    // @property (nonatomic, strong, readonly) RACSignal<NSError *> *errors;
    // @property (atomic, assign) BOOL allowsConcurrentExecution;
    // - (instancetype)initWithSignalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;
    // - (instancetype)initWithEnabled:(nullable RACSignal<NSNumber *> *)enabledSignal signalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;
    // - (RACSignal<ValueType> *)execute:(nullable InputType)input;
    // @end
    
    // RACCommand 中存在4种信号
    // 1. executionSignals
    // 2. executing
    // 3. enabled
    // 4. errors
    
    
    // RACCommand:
    // AC中用于处理事件的类，可以把事件如何处理，事件中的数据如何传递，包装到这个类中，它可以很方便的监控事件的执行过程
    
    // RACCommand使用步骤
    // 1. 创建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
    // 2. 在 signalBlock中，创建 RACSignal，并且作为 signalBlock 的返回值
    // 3. 执行命令 -(RACSignal *)execute:(id)input
    
    // 第一种就是直接通过传进一个用于构建 RACSignal 的 block 参数来初始化 RACCommand，而 block 中的参数 input 为执行 command 时传入的数据
    // 创建出的 signal 可在里面完成一些数据操作，如网络请求，本地数据库读写等等
    RACCommand<NSString *, NSString *> *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal<NSString *> * _Nonnull(NSString * _Nullable inputValue) {
        NSLog(@"inputValue = %@", inputValue);
        RACSignal<NSString *> *signal = [RACSignal<NSString *> createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@"Output Value"];
            [subscriber sendCompleted];
            return nil;
        }];
        return signal;
    }];
    
    // allowsConcurrentExecution 是一个 BOOL 类型的变量，它是用来表示当前 RACCommand 是否允许并发执行，默认值是NO
    // 如果 allowsConcurrentExecution 为 NO，那么 RACCommand 在执行过程中，enabled 信号就一定都返回 NO，不允许并发执行
    command.allowsConcurrentExecution = NO;
    self.command = command;
    
    // executionSignals
    // 一个高阶信号，使用时需要进行讲解操作
    // 降阶方式常用的有 flatten / switchToLatest / concat
    // 选择原则是，如果在不允许 Concurrent 并发的 RACCommand 中一般使用 switchToLatest；如果在允许 Concurrent 并发的 RACCommand 中一般使用 flatten
    [command.executionSignals subscribeNext:^(RACSignal<NSString *> * _Nullable x) {
        [x subscribeNext:^(NSString * _Nullable outputValue) {
            NSLog(@"outputValue - %@", outputValue);
        }];
    }];
    
    // 对 executionSignals 这个高阶信号进行降阶后订阅
    // [command.executionSignals.switchToLatest subscribeNext:^(NSString * _Nullable x) {
    //     NSLog(@"End - %@", x);
    // }];
    
    // RACCommand 初始化传入的 enabledSignal 信号，如果返回 NO，那么 enabled 信号就返回 NO
    // RACCommand 开始执行中，allowsConcurrentExecution 为 NO，那么 enabled 信号就返回 NO
    // 否则 enabled 信号就返回 NO
    [command.enabled subscribeNext:^(NSNumber * _Nullable x) {
        NSLog(@"enabled - %@", x ? @"YES" : @"NO");
    }];
    
    // '执行'信号
    // 信号中的至为 YES，表示 RACCommand 正在执行中；NO 表示的是 RACCommand 没有被执行或者已经执行结束
    // 在对 RACCommand 进行错误处理的时候，我们不应该使用 subscribeError: 对 RACCommand 的 executionSignals 进行订阅，因为 executionSignals 这个信号是不会发送 error 事件的
    [command.executing subscribeNext:^(NSNumber * _Nullable x) {
        NSLog(@"executing - %@", x.boolValue ? @"YES" : @"NO");
    }];
    
    // '错误'信号
    [command.errors subscribeNext:^(NSError * _Nullable x) {
        NSLog(@"errors subscribeNext = %@", x);
    }];
    
    [self.command execute:@"Input Value"];
}

- (void)demo21 {
    // 以下代码将输出
    // Subscriber will send next to subscriber
    // Subscriber1, x = Hello World
    // Subscriber will send next to subscriber
    // Subscriber2, x = Hello World
    
    RACSignal<NSString *> *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriberA) {
        NSLog(@"SubscriberA will send next to subscriber");
        [subscriberA sendNext:@"Hello World"];
        return nil;
    }];
    
    [signalA subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"Subscriber1, x = %@", x);
    }];

    [signalA subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"Subscriber2, x = %@", x);
    }];
    
    // 以下代码的输出
    // Subscriber will send next to subscriber
    // Subscriber3, x = Hello World
    // Subscriber4, x = Hello World
   
    RACSignal<NSString *> *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriberB) {NSLog(@"SubscriberB will send next to subscriber");
        [subscriberB sendNext:@"Hello World"];
        return nil;
    }];
    
    RACMulticastConnection<NSString *> *connect = [signalB publish];
    
    [connect.signal subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"Subscriber3, x = %@", x);
    }];
    
    [connect.signal subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"Subscriber4, x = %@", x);
    }];
    
    [connect connect];

}

/** KVO */
- (void)demo22 {
    UIView *colorView = [[UIView alloc] init];
    colorView.backgroundColor = [UIColor orangeColor];
    [self.view addSubview:colorView];
    [colorView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.mas_equalTo(self.view);
        make.width.and.height.mas_equalTo(200);
    }];
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
    [tap.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
        colorView.backgroundColor = [UIColor redColor];
    }];
    [colorView addGestureRecognizer:tap];
    
    
    [[colorView rac_valuesAndChangesForKeyPath:@keypath(colorView, backgroundColor) options:NSKeyValueObservingOptionNew observer:self] subscribeNext:^(RACTwoTuple<UIColor *, NSDictionary *> * _Nullable x) {
        UIColor *backgroundColor = x.first;
        NSLog(@"BackgroundColor %@ red", backgroundColor == [UIColor redColor] ? @"is" : @"is not");
    }];
    
    [[RACObserve(colorView, backgroundColor) skip:1] subscribeNext:^(UIColor * _Nullable x) {
        NSLog(@"BackgroundColor %@ red", x == [UIColor redColor] ? @"is" : @"is not");
    }];
}

- (void)demo23 {
    UITextField *textField = [[UITextField alloc] init];
    textField.textAlignment = NSTextAlignmentCenter;
    textField.borderStyle = UITextBorderStyleRoundedRect;
    textField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:textField];
    [textField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillChangeFrameNotification object:nil] subscribeNext:^(NSNotification * _Nullable noti) {
        NSLog(@"noti = %@", noti);
    }];
}

- (void)demo24 {
    // 同步多个信号
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:1];
            dispatch_async(dispatch_get_main_queue(), ^{
                [subscriber sendNext:@"Hello"];
                [subscriber sendCompleted];
            });
        });
        return nil;
    }];
    
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:2];
            dispatch_async(dispatch_get_main_queue(), ^{
                [subscriber sendNext:@"World"];
                [subscriber sendCompleted];
            });
        });
        return nil;
    }];
    
    [self rac_liftSelector:@selector(combineStrA:strB:) withSignalsFromArray:@[signalA, signalB]];
}

- (void)combineStrA:(NSString *)strA strB:(NSString *)strB {
    NSLog(@"%@ %@", strA, strB);
}

/** 对比 RAC 宏与信号订阅 */
- (void)demo25 {
    UITextField *textField = [[UITextField alloc] init];
    textField.textAlignment = NSTextAlignmentCenter;
    textField.borderStyle = UITextBorderStyleRoundedRect;
    textField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:textField];
    [textField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];
    
    UILabel *label1 = [UILabel new];
    label1.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:label1];
    [label1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.and.right.equalTo(textField);
        make.top.equalTo(textField.mas_bottom).mas_offset(8);
        make.height.equalTo(textField);
    }];
    
    UILabel *label2 = [UILabel new];
    label2.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:label2];
    [label2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.and.right.equalTo(label1);
        make.top.equalTo(label1.mas_bottom).mas_offset(8);
        make.height.equalTo(label1);
    }];
    
    [textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
        label1.text = x;
    }];

    RAC(label2, text) = textField.rac_textSignal;
}

- (void)demo26 {
    UITextField *textField = [[UITextField alloc] init];
    textField.textAlignment = NSTextAlignmentCenter;
    textField.borderStyle = UITextBorderStyleRoundedRect;
    textField.font = [UIFont systemFontOfSize:16];
    [self.view addSubview:textField];
    [textField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).mas_offset(8);
        make.right.equalTo(self.view).mas_offset(-8);
        make.top.equalTo(self.mas_topLayoutGuideBottom).mas_offset(8);
    }];

    // RACSignalBindBlock
    // 一个接受一个 RACSignal 并返回一个新 RACSignal 的 block
    // typedef RACSignal * _Nullable (^RACSignalBindBlock)(ValueType _Nullable value, BOOL *stop);
    
    // bind
    [[textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull(void) {
        return ^RACSignal * _Nullable(NSString * _Nullable value, BOOL *stop) {
           return [RACSignal return:[NSString stringWithFormat:@"'%@'", value]];
        };
    }] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"x = %@", x);
    }];
    
    // flattenMap
    [[textField.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:[NSString stringWithFormat:@"'%@'", value]];
            [subscriber sendCompleted];
            return nil;
        }];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"x = %@", x);
    }];
    
    // map
    [[textField.rac_textSignal map:^NSString * _Nullable(NSString * _Nullable value) {
        return [NSString stringWithFormat:@"'%@'", value];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"x = %@", x);
    }];
}

- (void)demo27 {
    RACSignal<NSString *> *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"Hello"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal<NSString *> *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"World"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    // concat:
    // 按一定顺序拼接信号，当多个信号发出的时候，有顺序的接收信号
    RACSignal<NSString *> *signalConcated = [signalA concat:signalB];
    
    [signalConcated subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"%@", x);
    }];
}

- (void)demo28 {
    RACSignal<NSString *> *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"Hello"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal<NSString *> *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"World"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    // merge:
    // 把多个信号合并成一个信号
    RACSignal *mergeSignal = [signalA merge:signalB];
    
    [mergeSignal subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
}

- (void)demo29 {
    RACSignal<NSString *> *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"Hello"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal<NSString *> *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"World"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal<RACTwoTuple<NSString *, NSString *> *> *zipSignal = [signalA zipWith:signalB];
    
    [zipSignal subscribeNext:^(RACTwoTuple<NSString *,NSString *> * _Nullable x) {
        RACTupleUnpack(NSString *valueA, NSString *valueB) = x;
        NSLog(@"valueA = %@, valueB = %@", valueA, valueB);
    }];
}

- (void)demo30 {
    RACSignal<NSString *> *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"Hello"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal<NSString *> *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"World"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal<RACTwoTuple<NSString *, NSString *> *> *signalCombined = [signalA combineLatestWith:signalB];
    [signalCombined subscribeNext:^(RACTwoTuple<NSString *, NSString *> * _Nullable x) {
        RACTupleUnpack(NSString *strA, NSString *strB) = x;
        NSLog(@"strA = %@, strB = %@", strA, strB);
    }];
}

- (void)demo31 {
    [[RACSignal<NSDate *> interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(NSDate * _Nullable x) {
        NSLog(@"[NSThread currentThread].isMainThread = %@", [NSThread currentThread].isMainThread ? @"YES" : @"NO");
    }];
}

- (void)demo32 {
    RACSignal<NSString *> *signal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"Will sends the next value and completed to subscribers");
        [subscriber sendNext:@"Hello World"];
        [subscriber sendCompleted];
        return nil;
    }] delay:1];
    
    [signal subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"x = %@, [NSThread currentThread].isMainThread = %@", x, [NSThread currentThread].isMainThread ? @"YES" : @"NO");
    }];
}

@end
